# -*- coding: utf-8 -*-
"""
# File       : Instruments.py
# Time       ：2022/7/6 10:04
# Author     ：zhaoningning
# version    ：python 3.9.12
# Description：
"""
import pyvisa as visa
import time
import numpy as np
import serial
import vxi11

class InstrumentInitial(object):
    def __init__(self, instr_id):
        self.instr_id = instr_id
        self.rm = visa.ResourceManager()
        self.dev_connect_visa = False
        self.dev_list = self.rm.list_resources()
        self.inst = None
        self.list_connected_devices()

    def instr_initial(self):

        self.inst = self.rm.open_resource('{}'.format(self.instr_id))

    @property
    def F(self):
        return self.inst.query("*IDN?")

    def write_command(self, command):
        self.inst.write(command)

    def query_command(self, command):
        return self.inst.query(command)

    def list_connected_devices(self):
        self.dev_list = self.rm.list_resources()
        self.dev_connect_visa = False
        # 'IP:169.254.174.89'   # 'TCPIP0::169.254.174.89::inst0::INSTR'
        # 'GPIB:2'      # 'GPIB0::12::INSTR'
        if 'IP' in self.instr_id:
            self.instr_id = 'TCPIP0::{}::inst0::INSTR'.format(self.instr_id.split(':')[1])
        elif 'GPIB' in self.instr_id:
            self.instr_id = 'GPIB0::{}::INSTR'.format(self.instr_id.split(':')[1])
        else:
            print(
                "\033[0;37;41mERROR: Unrecognized instrument interface types, only IP and GPIB can be recognized !!\033[0m")

        for dev_ in self.dev_list:
            if self.instr_id in dev_:
                self.dev_connect_visa = True
        if not self.dev_connect_visa:
            print(
                "\033[0;37;41mERROR: The instrument is not linked to VISA !!\033[0m")
# 数字万用表类
class DigitalMultimeterSDM3065X(InstrumentInitial):
    def __init__(self, dev_id):
        InstrumentInitial.__init__(self, dev_id)
        self.instr_initial()

    def clear_state(self):
        # 清除状态命令。清除所有寄存器组中的事件寄存器。也会清除错误队列。
        self.write_command('*CLS')  #

    def reset_dev(self):
        # 将仪器恢复为出厂默认状态
        self.write_command('*RST')

    def dc_voltage(self, counts=1, plc=0.005):
        # 等待 测量完成并将所有可用的测量结果复制到仪器的输出缓冲区
        self.write_command('CONF:VOLT:DC')
        # self.write_command('TRIG:SOUR IMM')  # 设置触发源为立即触发
        self.write_command('VOLT:DC:NPLC {}'.format(plc))

        self.write_command('SAMP:COUN {}'.format(counts))  # 设置采样次数

        voltage_str = self.query_command('READ?')[:-1]  # 读取本次测量生成的测量值
        voltage_out = []
        for voltage in voltage_str.split(','):
            voltage_out.append(float(voltage))
        return voltage_out

    def measure_dc_current(self, wait_time=2):
        # counts = 1
        ret = self.query_command('MEAS:CURR:DC?')
        time.sleep(wait_time)
        current = float(ret.replace('\n', ''))
        return current

    def measure_dc_voltage(self, wait_time=2):
        # counts = 1
        ret = self.query_command('MEAS:VOLT:DC?')
        time.sleep(wait_time)
        voltage = float(ret.replace('\n', ''))
        return voltage
# 示波器类
class OscilloscopeSDS2504X(InstrumentInitial):
    def __init__(self, dev_id):
        InstrumentInitial.__init__(self, dev_id)
        self.instr_initial()
# 电子负载类
class DP832A(InstrumentInitial):
    def __init__(self, dev_id):
        InstrumentInitial.__init__(self, dev_id)
        self.instr_initial()

    def set_voltage_current(self, channel, voltage, current=1):
        self.write_command(':APPL CH{},{},{}'.format(channel, voltage, current))

    def channel_state(self, channel, state):
        self.write_command(':OUTP CH{},{}'.format(channel, state.upper()))
class GPO2303s(InstrumentInitial):
    def __init__(self, dev_id):
        InstrumentInitial.__init__(self, dev_id)
        self.instr_initial()

    def set_voltage_current(self, channel, voltage, current=1):
        self.write_command('VSET{}:{}'.format(channel, round(voltage, 3)))
        self.write_command('ISET{}:{}'.format(channel, current))

    def channel_state(self, state):
        if 'ON' in state.upper():
            self.write_command('OUT1')
        elif 'OFF' in state.upper():
            self.write_command('OUT0')
        else:
            print("\033[0;37;41mERROR: Command Error !!\033[0m")
class Keysight34461A(InstrumentInitial):
    def __init__(self, dev_id):
        InstrumentInitial.__init__(self, dev_id)
        self.instr_initial()


    def clear_state(self):
        # 清除状态命令。清除所有寄存器组中的事件寄存器。也会清除错误队列。
        self.write_command('*CLS')  #

    def reset_dev(self):
        # 将仪器恢复为出厂默认状态
        self.write_command('*RST')

    def dc_voltage(self, counts=1, plc=0.02):
        # 等待 测量完成并将所有可用的测量结果复制到仪器的输出缓冲区
        self.write_command('CONF:VOLT:DC {}, 0.003'.format(plc))
        self.write_command('VOLT:DC:RANG:AUTO ON')  # 设置电压量程自动调整
        self.write_command('TRIG:SOUR IMM')  # 设置触发源为立即触发
        self.write_command('SAMP:COUN {}'.format(counts))  # 设置采样次数
        voltage_str = self.query_command('READ?')[:-1]  # 读取本次测量生成的测量值
        voltage_out = []
        for voltage in voltage_str.split(','):
            voltage_out.append(float(voltage))
        return voltage_out

    def dc_voltage_counts(self, counts=10, plc=0.02):
        # 等待 测量完成并将所有可用的测量结果复制到仪器的输出缓冲区
        self.write_command('CONF:VOLT:DC {},0.003'.format(plc))
        self.write_command('VOLT:DC:RANG:AUTO ON')  # 设置电压量程自动调整
        # self.write_command('VOLT:DC:RANG:MAX')  # 设置电压量程自动调整
        self.write_command('TRIG:SOUR BUS')  # 设置触发源为等待触发
        self.write_command('SAMP:COUN {}'.format(counts))  # 设置采样次数
        self.write_command('INIT')
        self.write_command('*TRG')
        time.sleep(0.1)
        voltage_str = self.query_command('FETC?')[:-1]  # 读取本次测量生成的测量值
        # vol = voltage_str.split(',')[0]
        voltage_float = []
        for vol in voltage_str.split(','):
            voltage_float.append(float(vol))
        print(np.mean(voltage_float))
        return np.mean(voltage_float)

    def measure_dc_current(self, wait_time=2):
        # counts = 1
        ret = self.query_command('MEAS:CURR:DC?')
        time.sleep(wait_time)
        current = float(ret.replace('\n', ''))
        return current
""""电子负载"""
class IT8510():
    def __init__(self, comport) -> None:
        self.session = serial.Serial(comport, 9600, timeout=1)


    def getID(self):
        self.session.write(b'*ver\r\n')
        time.sleep(0.1)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt)
        debugPrint(ret)

    def set_temp(self, temp):
        self.session.write(b's=%f\r\n' % temp)
        time.sleep(1)

    def set_sr(self, scanrate):
        self.session.write(b'sr=%d\r\n' % scanrate)
        time.sleep(1)

    def read_state(self):
        # 0 不稳定 1稳定
        self.session.write(b'st\r\n')
        time.sleep(0.1)
        cnt = self.session.in_waiting
        # ret = self.session.read(cnt).decode().split(':')[1].rstrip('\n')
        ret = self.session.read(cnt).decode().split(':')[1].rstrip('\n')
        # ret = self.session.read(cnt).decode()
        debugPrint(ret)
        return ret

"""温箱"""
class GHS_64():
    def __init__(self, comport) -> None:
        self.session = serial.Serial(comport, 9600, timeout=0.5)
    def temp_read(self):
        """
        读取设备温度
        Returns:
        """
        self.session.write(b'TEMP?\n')
        time.sleep(0.5)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt).decode().split(",")#.split(':')[1].rstrip('\n')
        debugPrint(ret[0])
        return ret[0]

    def read_current_HUMI(self):
        self.session.write(b'HUMI?\n')
        time.sleep(0.5)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt).decode().split(",")#.split(':')[1].rstrip('\n')
        debugPrint(ret[0])
        return ret[0]
    def getID(self):
        self.session.write(b',*ver\r\n')
        time.sleep(0.1)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt)
        debugPrint(ret)

    def set_temp(self, temp):
        self.session.write(b'TEMP S%f H100.0 L-40.0\n' % temp)
        time.sleep(0.1)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt)
        debugPrint(ret)

    def set_humi(self, humi):
        self.session.write(b'HUMI S%f H100 L0\n' % humi)

    def read_current_MODE(self):
        self.session.write(b'MODE?\n')
        time.sleep(0.5)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt).decode()  # .split(':')
        print(ret)
        return ret

    def write_power(self, start):
        if start == 1:
            self.session.write(b'POWER, ON')
        else:
            self.session.write(b'POWER, OFF')

    def date_read(self):
        self.session.write(b'DATE?\n')
        time.sleep(0.5)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt).split(b'.')
        date = [ret[0]] + ret[1].split(b'/')
        year = int(date[0]) + 2000
        month=int(date[1])
        day=int(date[2])
        DATE = ('{0}-{1}-{2}').format(year, month, day)
        return DATE

    def close(self):
        try:
            self.session.close()
        except Exception:
            pass

    def temp_set(self, setpoint=25, maximum=110, minimum=-45):
        if setpoint is not None and minimum is not None and maximum is not None:
            (self.session.write[bytes('TEMP, S{0:.1f} H{0:.1f} L{0:.1f}'.format(setpoint, maximum, minimum))]).decode()
            #self.ctlr.interact('TEMP, S%0.1f H%0.1f L%0.1f' % (setpoint, maximum, minimum))
        else:
            if setpoint is not None:
                (self.session.write('TEMP, S{0:.1f}'.format(setpoint))).decode('utf-8', 'replace')
            if minimum is not None:
                (self.session.write('TEMP, L{0:.1f}'.format(minimum))).decode('utf-8', 'replace')
            if maximum is not None:
                (self.session.write('TEMP, H{0:.1f}'.format(maximum))).decode('utf-8', 'replace')
                
"""示波器"""
class LECROY_HD9000():
    def __init__(self, ipaddr) -> None:
        self.session = vxi11.Instrument(ipaddr)

    def setOffset(self, chnn, ofst):
        """
        <channel>:= <C1 to Cn>
        <offset>:= <any valid value>
        """
        self.session.write('%s:OFFSET %sV' % (chnn, ofst))

    def setTimeDiv(self, tdiv):
        """
        <value>:= <any valid value>
        """
        self.session.write('TIME_DIV %E' % tdiv)

    def setTrigDelay(self, tdel):
        """
        <value>:= <any valid value>
        """
        self.session.write('TRIG_DELAY %E' % tdel)

    def setVoltDiv(self, chnn, vdiv):
        """
        <channel>:= <C1 to Cn>
        <v_gain>:= <any valid value><unit=V>
        """
        self.session.write('%s:VOLT_DIV %sV' % (chnn, vdiv))

    def setAutoMode(self):
        self.session.write('TRIG_MODE AUTO')

    def setNormalMode(self):
        self.session.write('TRIG_MODE Normal')

    def setSingleMode(self):
        self.session.write('TRIG_MODE SINGLE')

    def setStopMode(self):
        self.session.write('TRIG_MODE Stop')

    def getTrigMode(self):
        ret = self.session.ask('TRIG_MODE?')
        debugPrint(ret)
        return ret

    def setTrigTypeSrc(self, type, src):
        """
        type:DROP,EDGE,GLIT,INTV,PA,RUNT,SLEW,SQ,TEQ,TEQ1,SNG,STD
        src:C1,C2,Cn
        """
        self.session.write('TRIG_SELECT %s,SR,%s' % (type, src))

    def setTrigSlope(self, src, slope):
        """
        <trig_source>:= {C1, C2, C3, C4, LINE, EX, EX10, ETM10}
        <trig_slope>:= {NEG, POS}
        """
        self.session.write('%s:TRIG_SLOPE %s' % (src, slope))

    # def setTrigSlope(self, src, slope):
    #     """
    #     <trig_source>:= {C1, C2, C3, C4, LINE, EX, EX10, ETM10}
    #     <trig_slope>:= {NEG, POS}
    #     """
    #     self.session.write('%s:CURSOR_MEASURE %s' % (src, slope))

    def setTrigLevel(self, src, level):
        """
        <trig_source>:= <C1 to Cn, EX, EX10, ETM10>
        <trig_level>V
        """
        self.session.write('%s:TRIG_LEVEL %sV' % (src, level))

    def setDispOn(self, chnn):
        """
        <trace>:= C1 to Cn, F1 to Fn, TA to TD
        """
        self.session.write('%s:TRACE ON' % chnn)

    def setDispOff(self, chnn):
        """
        <trace>:= C1 to Cn, F1 to Fn, TA to TD
        """
        self.session.write('%s:TRACE OFF' % chnn)

    def setLabel(self, chnn, label: str):
        self.session.write('%s:TRACE_LABEL %s' % (chnn, label))

    def getParameterCustom(self, col):
        ret = self.session.ask('PACU? %s' % col)
        debugPrint(ret)
        return ret

    def deletePACU(self, col):
        self.session.write('PADL %s' % col)

    def setParameterCustom(self, col, meastyp, chnn):
        print('PACU %s,%s,C%s' % (col, meastyp, chnn))
        self.session.write('PACU %s,%s,C%s' % (col, meastyp, chnn))
        # print('PACU %s,%s,C%s' % (col, meastyp, chnn))

    def getValuePACU(self, meastyp, chnn):
        '''
        Frequency, Duty cycle:DUTY, Mean:MEAN
        '''
        ret = self.session.ask('C%s:PAVA? %s' % (chnn, meastyp))
        debugPrint(ret)
        if 'UNDEF' in ret.split(',')[1]:
            return 'UNDEF'
        else:
            # debugPrint(ret.split(',')[1].split(' ')[0])
            return float(ret.split(',')[1].split(' ')[0])

    def saveScreenImg(self, dirpath, filename):
        """
        HARDCOPY_SETUP DEV,<device>,FORMAT,<format>,BCKG,<bckg>,
        DEST,<destination>,DIR,"<directory>",AREA,<hardcopyarea>
        [,FILE,"<filename>",PRINTER,"<printername>",PORT,<portname>]
        <device>:= {BMP, JPEG, PNG, TIFF}
        <format>:= {PORTRAIT, LANDSCAPE}
        <bckg>:= {BLACK, WHITE}
        <destination>:= {PRINTER, CLIPBOARD, EMAIL, FILE, REMOTE}
        <area>:= {GRIDAREAONLY, DSOWINDOW, FULLSCREEN}
        <directory>:= legal DOS path, for FILE mode only
        <filename>:= filename string, no extension, for FILE mode only
        <printername>:= valid printer name, for PRINTER mode only
        <portname>:= {GPIB, NET}
        """
        self.session.write('HCSU DEV,PNG,FORMAT,PORTRAIT,BCKG,BLACK,DEST,FILE,DIR,"%s",AREA,GRIDAREAONLY,FILE,"%s"' % (
        dirpath, filename))
        self.session.ask('INR?')
        time.sleep(0.5)
        self.session.write('SCDP')
DEBUG = 0
def debugPrint(msg):
    if DEBUG:
        print(msg)


if __name__ == '__main__':
    keysight=Keysight34461A('169.254.4.61')
    counts = 1
    plc = 0.02
    voltages = keysight.dc_voltage(counts, plc)
    print(voltages)
    #==================test====================

    
    
    # print(visa.ResourceManager().list_resources())
    instrument = ('TCPIP::169.254.249.140::INSTR')
    instrument.saveScreenImg(r'D:\py_project\EquipmentAuto\000\000\Instrument','a.jpg')
    
    # LECROY_HD9000()
    
    # ghs_64 = GHS_64('COM13')
    # ghs_64.getID()
    # ghs_64.temp_read()
    # setpoint, maximum, minimum = 110, 111, 109
    # 
    # setpoint, maximum, minimum = 110, 111, 109
    # if setpoint is not None and minimum is not None and maximum is not None:
    #     (self.session.write('TEMP, S{0:.1f} H{0:.1f} L{0:.1f}'.format(setpoint, maximum, minimum))).decode('utf-8', 'replace')
    #     #self.ctlr.interact('TEMP, S%0.1f H%0.1f L%0.1f' % (setpoint, maximum, minimum))
    # else:
    #     if setpoint is not None:
    #         (self.session.write('TEMP, S{0:.1f}'.format(setpoint))).decode('utf-8', 'replace')
    #     if minimum is not None:
    #         (self.session.write('TEMP, L{0:.1f}'.format(minimum))).decode('utf-8', 'replace')
    #     if maximum is not None:
    #         (self.session.write('TEMP, H{0:.1f}'.format(maximum))).decode('utf-8', 'replace')






    def write_humi(self, **kwargs):
        '''
        update the humidity parameters

        Args:
            enable: boolean
            setpoint: float
            max: float
            min: float
            range: {"max":float,"min":float}
        '''
        setpoint, maximum, minimum = kwargs.get('setpoint'), kwargs.get('max'), kwargs.get('min')
        enable = kwargs.get('enable')
        if enable is False:
            spstr = 'SOFF'
        elif setpoint is not None:
            spstr = ' S{0:.1f}'.format(setpoint)
            #spstr = ' S%0.1f' % setpoint
        else:
            spstr = None
        if spstr is not None and minimum is not None and maximum is not None:
            #self.ctlr.interact('HUMI,%s H%0.1f L%0.1f' % (spstr, maximum, minimum))
            (self.ctlr.interact('HUMI,{} H{0:.1f} {0:.1f}'.format(spstr, maximum, minimum))).decode('utf-8', 'replace')
        else:
            if spstr is not None:
                self.ctlr.interact('HUMI,' + spstr)
            if minimum is not None:
                self.ctlr.interact('HUMI, L%0.1f' % minimum)
            if maximum is not None:
                self.ctlr.interact('HUMI, H%0.1f' % maximum)


    # big_osc = LECROY_HD9000('169.254.249.140')
    # big_osc.setNormalMode()
    # time.sleep(0.5)
    # big_osc.setSingleMode()
    # big_osc.session.write('PACU 1,SKEW,C1,POS,{0}E-3 V,C2,POS,{1}E-3 V,0 DIV,0 DIV'.format(0.5, 0.5))
    # big_osc.session.write('PACU 2,SKEW,C1,NEG,{0}E-3 V,C2,NEG,{1}E-3 V,0 DIV,0 DIV'.format(0.1, 0.1))
    # time.sleep(0.5)
    # big_osc.saveScreenImg(dirpath='E:\\project\\MBUS\\TS6628' + r'\\',
    #                       filename='LSF0108_A7_up_vcca={}V_vccb={}V_50pF'.format(vdd_1, vdd_2))
    #
    # #



